home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
476-500
/
disk_494
/
vscreen
/
source
/
vscreen.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-06
|
14KB
|
448 lines
/*
* VSCREEN.C Creates virtual screens that can be larger than
* the actual display area of your monitor. The virtual
* screen scrolls when the mouse moves off the edge of
* the display.
*
* Copyright 1988 by Davide P. Cervone, all rights reserved.
*
* You may distibute this code as is, for non-commercial
* purposes, provided that this notice remains intact and the
* documentation file is distributed with it.
*
* You may not modify this code nor incorporate it into your
* own programs without the permission of the author.
*/
/*
* WARNING: This code uses and even modifies the INTUITIONPRIVATE
* area of the IntuitionBase structure. Use it at your own risk. It is
* likely to break under a future release of Intuition.
*/
#include "vScreen.h"
static char *program = "vScreen"; /* the program name */
static char *author = COPYRIGHT; /* the copyright notice */
#define LOADVERS 1 /* this program's version */
static char *handler = "L:vScreen-Handler"; /* the name of the handler */
#define HANDLER &(handler[2]) /* same but in the current dir */
extern struct LayersBase *LayersBase; /* the Layers library */
struct vScreenInfo *vScreenData; /* data needed by the handler */
struct Screen *VScreen = NULL; /* the virtual screen */
static long Segment = NULL; /* the loaded handler */
SHORT ScreenWidth,ScreenHeight; /* the new screen sizes */
static struct MsgPort *NamedPort = NULL; /* used to find the handler later */
static struct MsgPort *InputPort = NULL; /* to talk to Input.Device */
static struct IOStdReq *InputBlock = NULL; /* IO block for Input.Device */
static short InputDevice = FALSE; /* is Input.Device open? */
static int Enlarged = FALSE; /* is screen changed? */
/*
* These routines are in vScreenSetup.c
*/
extern struct Screen *FindScreen();
extern void SetVariables();
extern void GetVariables();
extern int EnlargeScreen();
extern void RestoreScreen();
#ifndef PROTO
extern long SetFunction();
#endif
/*
* We trap these routines via SetFunction in order to make vSscreen work.
*/
#ifndef PROTO
extern void MoveSprite();
extern void LoadView();
extern void AutoRequest();
extern void BuildSysRequest();
extern void CloseScreen();
#endif
extern long LVOMoveSprite;
extern long LVOLoadView;
extern long LVOAutoRequest;
extern long LVOBuildSysRequest;
extern long LVOCloseScreen;
/*
* CreateNonSigPort()
*
* Creates a message port with signal type PA_IGNORE. Based on
* CreatePort() from the exec support functions documented in the RKM.
*/
struct MsgPort *CreateNonSigPort(name,pri)
char *name;
BYTE pri;
{
struct MsgPort *thePort;
thePort = (struct MsgPort *)AllocMem((ULONG)sizeof(struct MsgPort),
MEMF_PUBLIC | MEMF_CLEAR);
if (thePort)
{
thePort->mp_Node.ln_Name = name;
thePort->mp_Node.ln_Pri = pri;
thePort->mp_Node.ln_Type = NT_MSGPORT;
thePort->mp_Flags = PA_IGNORE;
thePort->mp_SigBit = 0;
thePort->mp_SigTask = NULL;
if (name)
AddPort(thePort);
else
NewList(&(thePort->mp_MsgList));
}
return(thePort);
}
/*
* DeleteNonSigPort()
*
* Deletes a message port with signal type PA_IGNORE. Based on
* DeletePort() from the exec support functions documented in the RKM
*/
void DeleteNonSigPort(thePort)
struct MsgPort *thePort;
{
if (thePort->mp_Node.ln_Name) RemPort(thePort);
thePort->mp_Node.ln_Type = 0xFF;
thePort->mp_MsgList.lh_Head = (struct Node *) -1;
FreeMem(thePort,(ULONG)sizeof(struct MsgPort));
}
/*
* DoExit()
*
* Exit with error status. Print a message with up to three parameters
* and then clean up everything (restore the screen if it is enlarged,
* unload the handler if it is loaded, close the Input.Device and free
* its IO blocks and ports, and close any open libraries). Return the
* error status.
*/
void DoExit(s,x1,x2,x3)
char *s, *x1,*x2,*x3;
{
int status = OK_EXIT;
if (s)
{
printf(s,x1,x2,x3);
printf("\n");
status = ERROR_EXIT;
}
if (Enlarged) RestoreScreen();
if (NamedPort) DeleteNonSigPort(NamedPort);
if (Segment) UnLoadSeg(Segment);
if (InputDevice) CloseDevice(InputBlock);
if (InputBlock) DeleteStdIO(InputBlock);
if (InputPort) DeletePort(InputPort);
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (GfxBase) CloseLibrary(GfxBase);
if (LayersBase) CloseLibrary(LayersBase);
exit(status);
}
/*
* CheckLibOpen()
*
* Call OpenLibrary() for the specified library, and check that the
* open succeeded.
*/
void CheckLibOpen(lib,name,rev)
APTR *lib;
char *name;
int rev;
{
#ifndef PROTO
extern APTR OpenLibrary();
#endif
if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
DoExit("Can't open '%s'",name);
}
/*
* GetInt()
*
* Read the first integer from the given string variable (used to parse
* the command-line arguments). If no integer can be read, exit and
* show the usage string.
*/
static long GetInt(s)
char *s;
{
long i;
if (sscanf(s,"%ld",&i) != 1) DoExit("Usage: %s",USAGE);
return(i);
}
/*
* ParseArguments()
*
* Parse the command-line arguments. If there are too many or too few
* arguments, exit with an error message, otherwise get the width and height
* agruments. If there was a screen name specified, record that.
* Find the specified screen.
*/
static void ParseArguments(argc,argv)
int argc;
char *argv[];
{
char *ScreenName = NULL;
if (argc < 3) DoExit("Width and Height are required\nUsage: %s",USAGE);
if (argc > 4) DoExit("Too many arguments");
ScreenWidth = GetInt(argv[1]);
ScreenHeight = GetInt(argv[2]);
if (ScreenWidth <= 0 || ScreenHeight <= 0)
DoExit("Screen height and width must be positive");
if (ScreenWidth > 1024 || ScreenHeight > 1024)
printf("Warning: sizes greater than 1024 may cause Blitter problems\n");
if (argc > 3 && argv[3] && argv[3][0] != '\0') ScreenName = argv[3];
VScreen = FindScreen(ScreenName);
}
/*
* LoadHandler()
*
* Try to LoadSeg the handler from the current directory, and if it is not
* found, try the L: directory. If neither can be loaded, exit with a
* message. Once the handler is loaded, call its Setup routine passing it
* our version number. The handler will check the versions for compatability,
* and return NULL for version mismatch, or a pointer to its data structure
* with pointers to the variables that vScreen will initialize for it.
* LoadHandler() sets the pointer to the handlers SegList, and sets the
* loader version number
*/
static void LoadHandler()
{
struct vScreenInfo *(*Setup)();
if ((Segment = LoadSeg(HANDLER)) == NULL)
if ((Segment = LoadSeg(handler)) == NULL)
DoExit("Can't Load '%s'",handler);
Setup = (struct vScreenInfo *(*)()) ((Segment << 2) + 4);
vScreenData = (*Setup)(LOADVERS);
if (vScreenData)
{
if (var(MajVers) > 1) DoExit("version mismatch with '%s'",HANDLER);
} else {
DoExit("'%s' reports a version mismatch",HANDLER);
}
var(Segment) = Segment;
var(LoadVers) = LOADVERS;
}
/*
* TellInputDevice()
*
* Create a port and I/O block, then open the input device. Set up the
* I/O block to add or remove the input handler, and send the request
* to the input device. Finally, close the device and delete the
* I/O block and port.
*/
void TellInputDevice(function)
int function;
{
long status;
if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
if ((InputBlock = CreateStdIO(InputPort)) == NULL)
DoExit("Can't Create Standard IO Block");
InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
InputBlock->io_Command = (long) function;
InputBlock->io_Data = (APTR) vScreenData->HandlerInfo;
if (status = DoIO(InputBlock)) DoExit("Error from DoIO: %ld",status);
CloseDevice(InputBlock); InputDevice = FALSE;
DeleteStdIO(InputBlock); InputBlock = NULL;
DeletePort(InputPort); InputPort = NULL;
}
/*
* SetVectors()
*
* Call SetFunction() to replace the library vectores for the routines that
* we need to trap. Use the routines that the handler has supplied (they
* were passed to us in the vScreenData structure). Save the old vectors
* in the vScreenData strucutre so we can replace them later. Set the
* jump addresses so that the stub routines can call the old vectors.
* I Know this is a kludge, and is a form of self-modifying code, but I
* can't figure out a better method. The JSR (Ax) is only good when there
* is a free A register, which is not always the case.
*/
void SetVectors()
{
var(OldCloseScreen) =
SetFunction(IntuitionBase,&LVOCloseScreen,var(aCloseScreen));
var(CloseScreenJmpTarget)[-1] = (long) var(OldCloseScreen);
var(OldBuildSysRequest) =
SetFunction(IntuitionBase,&LVOBuildSysRequest,var(aBuildSysRequest));
var(BuildSysRequestJmpTarget)[-1] = (long) var(OldBuildSysRequest);
var(OldAutoRequest) =
SetFunction(IntuitionBase,&LVOAutoRequest,var(aAutoRequest));
var(AutoRequestJmpTarget)[-1] = (long) var(OldAutoRequest);
var(OldLoadView) = SetFunction(GfxBase,&LVOLoadView,var(aLoadView));
var(LoadViewJmpTarget)[-1] = (long) var(OldLoadView);
var(OldMoveSprite) = SetFunction(GfxBase,&LVOMoveSprite,var(aMoveSprite));
var(MoveSpriteJmpTarget)[-1] = (long) var(OldMoveSprite);
}
/*
* UnSetVectors()
*
* Put back the old jump vectors for the routines that we replaced.
* Make sure that no one else has replced them behind our backs, however.
* If they are not the same way we left them, return an error status.
*/
int UnSetVectors()
{
long NewCloseScreen,NewBuildSysRequest,NewAutoRequest,
NewLoadView,NewMoveSprite;
int status = TRUE;
NewCloseScreen =
SetFunction(IntuitionBase,&LVOCloseScreen,var(OldCloseScreen));
NewBuildSysRequest =
SetFunction(IntuitionBase,&LVOBuildSysRequest,var(OldBuildSysRequest));
NewAutoRequest =
SetFunction(IntuitionBase,&LVOAutoRequest,var(OldAutoRequest));
NewLoadView = SetFunction(GfxBase,&LVOLoadView,var(OldLoadView));
NewMoveSprite = SetFunction(GfxBase,&LVOMoveSprite,var(OldMoveSprite));
if (NewCloseScreen != (long) var(aCloseScreen) ||
NewBuildSysRequest != (long) var(aBuildSysRequest) ||
NewAutoRequest != (long) var(aAutoRequest) ||
NewLoadView != (long) var(aLoadView) ||
NewMoveSprite != (long) var(aMoveSprite))
{
SetFunction(IntuitionBase,&LVOCloseScreen,NewCloseScreen);
SetFunction(IntuitionBase,&LVOBuildSysRequest,NewBuildSysRequest);
SetFunction(IntuitionBase,&LVOAutoRequest,NewAutoRequest);
SetFunction(GfxBase,&LVOLoadView,NewLoadView);
SetFunction(GfxBase,&LVOMoveSprite,NewMoveSprite);
status = FALSE;
}
return(status);
}
/*
* main()
*
* Look for the vScreen port.
* If one does not exist then vScreen is not currently active, so
* open the intuition and graphics libraries.
* Parse the command-line arguments to get the width, height, and screen.
* Load the handler code, and check its version.
* Create the named port used to store information about the handler.
* Setup some of the variables needed by the handler, and save a pointer
* to the handler data in the named port.
* Try to enlarge the size of the screen bitmap, and set more variables.
* Add the input handler into the input chain.
* SetFunction the neede vectors. At this point vScreen is active.
* Print a message that reports the version numbers.
* Otherwise (the port already exists, so vScreen already is active)
* Get the pointer to the vScreenData structure from the port.
* If they user had supplied arguments, tell him vScreen already is running.
* Try to unset the routines we replaced earlier.
* If the vectors we removed successfully then
* Remove the input handler.
* Restore the screen to its original size.
* Delete the (no-longer-needed) named port.
* Unload the handler code.
* Tell the user that the code is removed.
* Close the libraries (note that these remained open between calls
* to vScreen, while the handler was active).
* Otherwise (we could not replce the function vectors)
* Report the problem, and leave the handler running.
*/
void main(argc,argv)
int argc;
char *argv[];
{
NamedPort = FindPort(PORTNAME);
if (NamedPort == NULL)
{
CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
ParseArguments(argc,argv);
LoadHandler();
if ((NamedPort = CreateNonSigPort(var(PortName),0L)) == NULL)
DoExit("Can't Create Message Port '%s'",var(PortName));
SetVariables(NamedPort);
Enlarged = EnlargeScreen();
TellInputDevice(IND_ADDHANDLER);
SetVectors();
printf("%s v%d.%d.%d Installed\n",program,
var(MajVers),var(MinVers),var(LoadVers));
} else {
GetVariables(NamedPort);
if (argc > 1)
{
printf("%s already active on screen '%s'\n",program,VScreen->Title);
} else {
if (UnSetVectors())
{
TellInputDevice(IND_REMHANDLER);
RestoreScreen();
DeleteNonSigPort(NamedPort);
UnLoadSeg(var(Segment));
printf("%s Removed\n",program);
CloseLibrary(IntuitionBase);
CloseLibrary(GfxBase);
} else {
printf("SetFunction vectors have been changed!\n");
printf("%s Not Removed\n",program);
}
}
}
}